
#include "PerlinNoise.hpp"

// Global Data:

Pixel3ub noiseImage[noiseImageHeight * noiseImageWidth];
static float rgb[2];

// Code:

inline float Interp(float a, float b, float c)
{
	return (a + (b - a) * c * c * (3 - 2 * c));
}

inline float Lerp(float a, float b, float c)
{
	return (a * (1 - c) + b * c);
}

inline float Noise(int x)
{
	x = (x << 13) ^ x;
	return (((x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 2147483648.0);
}

inline void GenColor(float val, unsigned char r, unsigned char g, unsigned char b)
{
	float fr = Lerp(0, r, val);
	float fg = Lerp(0, g, val);
	float fb = Lerp(0, b, val);

	rgb[0] = fr;
	rgb[1] = fg;
	rgb[2] = fb;
}

float PerlinNoise(float x, float y, int width, int octaves, int seed, double periode)
{
	double a, b, value, freq, zone_x, zone_y;
	int s, box, num, step_x, step_y;
	int amplitude = 120;
	int noisedata;

	value = 0;
	freq = 1.0 / periode;

	for (s = 0; s < octaves; ++s)
	{
		num = static_cast<int>(width * freq);
		step_x = static_cast<int>(x * freq);
		step_y = static_cast<int>(y * freq);
		zone_x = x * freq - step_x;
		zone_y = y * freq - step_y;
		box = step_x + step_y * num;
		noisedata = (box + seed);
		a = Interp(Noise(noisedata), Noise(noisedata + 1), zone_x);
		b = Interp(Noise(noisedata + num), Noise(noisedata + 1 + num), zone_x);
		value = Interp(a, b, zone_y) * amplitude;
	}

	return (value);
}

void CreateNoiseImage(float scale, int width, int seed, unsigned char r, unsigned char g, unsigned char b)
{
	float disp1, disp2, disp3, disp4, disp5, disp6;

	for (int y = 0; y < noiseImageWidth; ++y)
	{
		for (int x = 0; x < noiseImageHeight; ++x)
		{
			disp1 = PerlinNoise(x * scale, y * scale, width, 1, seed, 100);
			disp2 = PerlinNoise(x * scale, y * scale, width, 1, seed, 25.0);
			disp3 = PerlinNoise(x * scale, y * scale, width, 1, seed, 12.5);
			disp4 = PerlinNoise(x * scale, y * scale, width, 1, seed, 6.25);
			disp5 = PerlinNoise(x * scale, y * scale, width, 1, seed, 3.12);
			disp6 = PerlinNoise(x * scale, y * scale, width, 1, seed, 9.56);

			GenColor((int)disp1+(int)(disp2*0.25)+(int)(disp3*0.125)+(int)(disp4*0.0625)+(int)(disp5*0.03125)+(int)(disp6*0.0956), r, g, b);

			noiseImage[x + y * noiseImageWidth].r = static_cast<unsigned char>(rgb[0]);
			noiseImage[x + y * noiseImageWidth].g = static_cast<unsigned char>(rgb[1]);
			noiseImage[x + y * noiseImageWidth].b = static_cast<unsigned char>(rgb[2]);
		}
	}
}